home *** CD-ROM | disk | FTP | other *** search
/ Aminet 15 / Aminet 15 - Nov 1996.iso / Aminet / comm / bbs / s342q16.lha / slist.c < prev    next >
C/C++ Source or Header  |  1996-08-29  |  10KB  |  321 lines

  1. /*
  2. * SList.C
  3. *
  4. * Copyright (c) 1989 by Hue, Jr.  All Rights Reserved.
  5. *
  6. * This is a generic, messy list handler.
  7. * VARIANT: this one automatically sorts the list where allowed.
  8. */
  9. #include "ctdl.h"
  10. #include "stdio.h"
  11. #include "stdlib.h"
  12. #include "string.h"
  13. #include "slist.h"
  14. #define TRUE    1
  15. #define FALSE   0
  16. extern CONFIG    cfg;
  17. void  Do_Stack_Check(void);
  18. /*
  19. * History
  20. *
  21. * 89Jan22 HAW  Variant for keeping sorted lists.
  22. * 89Jan01 HAW  Completed initial version.
  23. */
  24. /************************************************************************/
  25. /*                              Contents                                */
  26. /*                                                                      */
  27. /*                      Generic Functions                               */
  28. /*                                                                      */
  29. /*      AddData()               Add an element of data to a list        */
  30. /*      KillData()              remove an element of data from a list   */
  31. /*      KillList()              Destroys a list                         */
  32. /*      MakeList()              Construct a disk-based list in memory   */
  33. /*      RunList()               run a function on a list                */
  34. /*      SearchList()            search a list for a given data element  */
  35. /*                                                                      */
  36. /************************************************************************/
  37. /*
  38. * Usage
  39. *
  40. * This module contains a generic list handler.
  41. *
  42. *  o Initialization - before a list can contain things, it must be
  43. *  initialized.  Initialization consists of declaring some variable to
  44. *  be of type SListBase (this variable will be what you use to access
  45. *  the list), and ensuring it is initialized correctly before use.
  46. *  Initialization may be accomplished either via initializers or
  47. *  manually.  In any case, this is what each field must be initialized
  48. *  to:
  49. *  - start -- initialize to NULL in ALL cases.
  50. *  - CheckIt -- initialize to point to a function capable of comparing
  51. *        two data structs for equality on some arbitrary, meaningful
  52. *        quality (specifically NOT the value of the void pointer itself!).
  53. *        If equal, it should return a pointer to some value which will be
  54. *        useful in that context, otherwise NULL.
  55. *  - cmp -- initialize to point to a function which accepts to two void *
  56. *        variables, i.e., must like qsort: cmp(void *s1, void *s2).  This
  57. *        function should return < 0 if s1 < s2, > 0 if s1 > s2, == 0 if the
  58. *        two variables are 'equal'.  If this field is NULL, then the list
  59. *        will not be sorted.
  60. *  - FreeFunc -- some function capable of freeing an unneeded data
  61. *        instance from the list.
  62. *  - EatLine -- some function capable of digesting a line of data from
  63. *        a text file and producing a pointer to a new data instance with
  64. *        the results of the digestion entombed within for later use.
  65. *
  66. *  o Briefly, here are the currently supported services for list
  67. *  handling.
  68. *  - MakeList will construct a list from the given text file, using the
  69. *        EatLine function outlined above.
  70. *  - AddData will add a single data element to the list.  Data element
  71. *        in toto must be provided by the user.  Optionally will kill
  72. *        duplicates (detected using CheckIt function) from list, optionally
  73. *        will "write" list after addition (very blind - check code).
  74. *  - KillData will kill the specified data element from the list, using
  75. *        CheckIt to find them.  All instances will be deleted.
  76. *  - KillList will kill the list.  (Not implemented yet.)
  77. *  - SearchList will search the list for the given data element, using
  78. *        CheckIt to detect it.  If found, a void * will be returned to the
  79. *        caller, for its own interpretation.  The pointer returned will be
  80. *        the same as that returned by the CheckIt function.
  81. *  - RunList will apply the specified function to all members of the
  82. *        list.
  83. *
  84. *  This module needs the function void *GetDynamic(int size) to be
  85. *  defined as a function which returns size bytes of dynamic memory.
  86. */
  87. /*
  88. * MakeList(SListBase *base, char *fn, FILE *fd)
  89. *
  90. * This function will construct a list by reading from a text file and asking
  91. * a specified function to process the text.  If strlen(fn) == 0, it will use
  92. * File fd passed in, otherwise it will try to open fn in text mode.
  93. */
  94. char MakeList(base, fn, fd)
  95. SListBase *base;
  96. char         *fn;
  97. FILE         *fd;
  98.   {
  99.   char        line[80];
  100.   void        *temp;
  101.   Do_Stack_Check();
  102.   if (strlen(fn))
  103.     {
  104.     if (cfg.BoolFlags.debug) splitF(NULL,"Open file:%s\n",fn);
  105.     if ((fd = fopen(fn, "r")) == NULL)return FALSE;
  106.  
  107.     }
  108.   while (GetAString(line, 80, fd) != NULL)
  109.     {
  110.     if (cfg.BoolFlags.debug) splitF(NULL,"eat line:%s\n",line);
  111.     if ((temp = (*base->EatLine)(line)) != NULL)
  112.       {
  113.       AddData(base, temp, NULL, FALSE);
  114.  
  115.       }
  116.  
  117.     }
  118.   if (strlen(fn)) fclose(fd);
  119.   if (cfg.BoolFlags.debug) splitF(NULL,"Closed:%s\n",fn);
  120.   return TRUE;
  121.  
  122.   }
  123. /*
  124. * char *GetAString(char *line, int size, FILE *fd)
  125. *
  126. * Gets a string from the file, chops off the EOL.  If EOF, returns NULL.
  127. */
  128. char *GetAString(char *line, int size, FILE *fd)
  129.   {
  130.   char *s;
  131.   Do_Stack_Check();
  132.   if (fgets(line, size, fd) != NULL)
  133.     {
  134.     if ((s = strchr(line, '\n')) != NULL)
  135.     *s = 0;
  136.     if ((s = strchr(line, '\r')) != NULL)
  137.     *s = 0;
  138.     return line;
  139.  
  140.     }
  141.   return NULL;
  142.  
  143.   }
  144. /************************************************************************/
  145. /*          AddData() Add an element of data to a list                  */
  146. /************************************************************************/
  147. void AddData(base, data, writeit, killdups)
  148. SListBase *base;
  149. void                *data;
  150. char                killdups;
  151. void                (*writeit)(void *data);
  152.   {
  153.   SListData *rover, *rover2, *trail = NULL;
  154.   Do_Stack_Check();
  155.   if (killdups)
  156.   KillData(base, data);
  157.   rover = (SListData *) GetDynamic(sizeof *rover);
  158.   if (base->start == NULL)
  159.     {
  160.     base->start = rover;
  161.     rover->next = NULL;
  162.  
  163.     }
  164.   else
  165.     {
  166.     for (rover2 = base->start;
  167.     rover2 != NULL &&
  168.     (base->cmp == NULL ||
  169.     (*base->cmp)(rover2->data, data) < 0) ;
  170.     rover2 = rover2->next)
  171.     trail = rover2;
  172.     if (trail == NULL)
  173.       {
  174.       rover->next = base->start;
  175.       base->start = rover;
  176.  
  177.       }
  178.     else
  179.       {
  180.       rover->next = trail->next;
  181.       trail->next = rover;
  182.  
  183.       }
  184.  
  185.     }
  186.   rover->data = data;
  187.   if (writeit != NULL)
  188.   RunList(base, writeit);
  189.  
  190.   }
  191. /************************************************************************/
  192. /*          KillData() remove an element of data from a list            */
  193. /************************************************************************/
  194. void KillData(base, data)
  195. SListBase *base;
  196. void        *data;
  197.   {
  198.   SListData *rover, *trail, *moo;
  199.   Do_Stack_Check();
  200.   if (base->CheckIt == NULL) return;
  201.   trail = base->start;
  202.   rover = base->start;
  203.   while (rover != NULL)
  204.     {
  205.     if ((*base->CheckIt)(rover->data, data) != NULL)
  206.       {
  207.       moo = rover->next;
  208.       (*base->FreeFunc)(rover->data);
  209.       free(rover);
  210.       if (trail == rover)
  211.       rover = trail = base->start = moo;
  212.       else
  213.       trail->next = rover = moo;
  214.  
  215.       }
  216.     else
  217.       {
  218.       trail = rover;
  219.       rover = rover->next;
  220.  
  221.       }
  222.  
  223.     }
  224.  
  225.   }
  226. /************************************************************************/
  227. /*          KillList() Destroys a list                                  */
  228. /************************************************************************/
  229. void KillList(base)
  230. SListBase *base;
  231.   {
  232.   SListData *rover, *b;
  233.   Do_Stack_Check();
  234.   for (b = base->start; b != NULL; )
  235.     {
  236.     rover = b->next;
  237.     (*base->FreeFunc)(b->data);
  238.     free(b);
  239.     b = rover;
  240.  
  241.     }
  242.   base->start = NULL;
  243.  
  244.   }
  245. /************************************************************************/
  246. /*          SearchList() search a list for a given data element         */
  247. /************************************************************************/
  248. void *SearchList(base, data)
  249. SListBase *base;
  250. void        *data;
  251.   {
  252.   SListData *rover;
  253.   void         *temp;
  254.   Do_Stack_Check();
  255.   for (rover = base->start; rover != NULL; rover = rover->next)
  256.   if ((temp = (*base->CheckIt)(rover->data, data)) != NULL)
  257.   return temp;
  258.   return NULL;
  259.  
  260.   }
  261. /************************************************************************/
  262. /*          RunList() run a function on a list                          */
  263. /************************************************************************/
  264. int RunList(base, doit)
  265. SListBase *base;
  266. void        (*doit)(void *data);
  267.   {
  268.   SListData *rover;
  269.   int       count = 0;
  270.   Do_Stack_Check();
  271.   for (rover = base->start; rover != NULL; rover = rover->next, count++)
  272.   (*doit)(rover->data);
  273.   return count;
  274.  
  275.   }
  276. /*
  277. * void FrontToEnd(SListBase *base)
  278. *
  279. * This function takes the first element of the list, if it exists, and makes
  280. * it the last element of the list.  This is useful for lists whose sort order
  281. * changes due to outside forces.
  282. */
  283. void FrontToEnd(base)
  284. SListBase *base;
  285.   {
  286.   SListData *r1, *r2;
  287.   Do_Stack_Check();
  288.   if (base->start != NULL && base->start->next != NULL)
  289.     {
  290.     r1 = base->start;
  291.     base->start = r1->next;
  292.     for (r2 = r1; r2->next != NULL; r2 = r2->next)
  293.     ;
  294.     r2->next = r1;
  295.     r1->next = NULL;
  296.  
  297.     }
  298.  
  299.   }
  300. void NoFree(void *d)
  301.   {
  302.   Do_Stack_Check();
  303.  
  304.   }
  305. /*
  306. * void *GetLast(SListBase *base)
  307. *
  308. * This function finds the last element in the list and returns it.  It
  309. * returns NULL if the list is empty.
  310. */
  311. void *GetLast(SListBase *base)
  312.   {
  313.   SListData *rover;
  314.   Do_Stack_Check();
  315.   if (base->start == NULL) return NULL;
  316.   for (rover = base->start; rover->next != NULL; rover = rover->next)
  317.   ;
  318.   return rover->data;
  319.  
  320.   }
  321.